#ifndef MY_INTERPRETER_H
#define MY_INTERPRETER_H

#include <cstdio>
#include <iostream>

using namespace std;

#include "interpreter.h"
#include "verifier.h"
#include "myaction.h"
#include "mystates.h"
       
class MyInterpreter : public Interpreter{
    private:
        int objectId;
        int faceId;
        int state;
    
        void beautification(map<int, Trace> &traces, int _id){
            Beautification::position(traces[_id]);
            if ( traces[_id].size() == 2 ){
                vector<Trace> ts;
                
                map<int, Trace>::iterator it;
                for (it = traces.begin(); it != traces.end(); it++){
                    ts.push_back(it->second);
                }
                if (traces.size() > 1){
                    Beautification::connections(ts, traces[_id]);
                    for (int i = 0; i < ts.size(); i++){
                        traces[ts[i].getId()] = ts[i];
                    }
                }
            }   
            else{
                traces.erase(_id);
            } 
        }
    
    public:
        MyInterpreter(){
            this->state = CREATE_POLYGON;
        }
        ~MyInterpreter(){}
        
        void createPolygon(int _id){
            map<int, Trace> &traces = this->sketch.getTraces();
            
            if ( modeling->getObjects().size() == 0){
                Object obj = modeling->factory.createObject();
                this->objectId = obj.getId();
                
                modeling->addObject( obj );
            }            
            
            // distancia em pixels
            if (traces[_id][0].distance(traces[_id][-1]) > 10){
                beautification(traces, _id);

                if (traces[_id].size() == 2){
                    DrawSegmentAction drawSegmentAction;
                    drawSegmentAction.setScene(scene);
                    drawSegmentAction.act(traces[_id]);
                    
                    PolygonVerifier verifier;
                    if( verifier.verifySketch(this->sketch) ){
                        PolygonAction polygonAction;
                        polygonAction.setVertices(verifier.getVertices());
                        polygonAction.setEdges(verifier.getEdges());
                        polygonAction.setScene(scene);
                        polygonAction.act(this->sketch);
                        
                        CreateFaceAction createFaceAction;
                        createFaceAction.setScene(scene);
                        createFaceAction.setPolygon( polygonAction.getPolygon() );
                        createFaceAction.setModeling(modeling);
                        createFaceAction.setObjectId(this->objectId);
                        createFaceAction.act();
                        this->faceId = createFaceAction.getFaceId();
                    }
                }
                else{
                    traces.erase(_id);
                }
            }
            else{
                traces.erase(_id);
            }  
        }    

        void selection(int _id){
            map<int, Trace> &traces = this->sketch.getTraces();
    
            SelectionAction selectionAction;
            selectionAction.setFaceId(this->faceId);
            selectionAction.setState(this->state);
            selectionAction.setScene(scene);
            selectionAction.setModeling(modeling);
            selectionAction.act(traces[_id][-1]);
            
            this->faceId = selectionAction.getFaceId();
//            printf("Face Id: %i\n",this->faceId);
            
            if (state == CREATE_POLYGON and selectionAction.getState() == FACE_SELECTED){
                this->state = FACE_SELECTED;
            }
            else{
                this->state = CREATE_POLYGON;
            }
        }
        
        void growSuggestion(int _id){
            printf("\nCrescer...\n");
            int r;
            printf("\n\nSugestões de crescimento:\n1: Prisma\n2: Piramide:\nResposta: ");
//            scanf("%i",&r);
            fflush(stdin);
            cin >> r;
            if (r == 1){
                printf("Prisma!!!\n");
                createPrisma(_id);
            }
            else if (r == 2){
                printf("Piramide!!!\n");
                createPyramid(_id);
            }
            else{
                printf("\n\nInvalid Operation!!!\n\n");
            }
        }    
        
        void createPrisma(int _id){
            map<int, Trace> &traces = this->sketch.getTraces();
            
            SegmentVerifier segmentVerifier;
            if ( segmentVerifier.verifyTrace( traces[_id] ) ){
                Beautification::position(traces[_id]);
                
                Point generatrix = traces[_id].getCursors()[1].getScenePoint() 
                                    - traces[_id].getCursors()[0].getScenePoint();
                modeling->createPrism(this->objectId, this->faceId, generatrix);
                this->state = CREATE_POLYGON;
            }            
            
        }
        
        void createPyramid(int _id){
            map<int, Trace> &traces = this->sketch.getTraces();
            
            SegmentVerifier segmentVerifier;
            if ( segmentVerifier.verifyTrace( traces[_id] ) ){
                Beautification::position(traces[_id]);
                
                Point generatrix = traces[_id].getCursors()[1].getScenePoint() 
                                    - traces[_id].getCursors()[0].getScenePoint();
                modeling->createPyramid(this->objectId, this->faceId, generatrix);
                this->state = CREATE_POLYGON;
            }            
            
        }        
        
        void preHandleState(){
            switch(this->state){
                case CREATE_POLYGON:
                    printf("PRE: CREATE_POLYGON\n");
                    break;
                case CREATE_PRISMA:
                    printf("PRE: CREATE_PRISMA\n");
                   break; 
                case FACE_SELECTED:
                    printf("PRE: FACE_SELECTED\n");
                   break; 
            }
            map<int, Trace> &traces = this->sketch.getTraces();
        }
        
        void postHandleState(){
            map<int, Trace> &traces = this->sketch.getTraces();
            switch(this->state){
                case CREATE_POLYGON:
                    printf("POST: CREATE_POLYGON\n\n");
                    scene->disablePlane();
                    break;
                case CREATE_PRISMA:
                    printf("POST: CREATE_PRISMA\n\n");
                    scene->enablePlane();
                   break; 
                case FACE_SELECTED:
                    printf("POST: FACE_SELECTED\n\n");
                    scene->disablePlane();
                   break; 
            }             
        }        
        
        void handleState(int _id){
            map<int, Trace> &traces = this->sketch.getTraces();
            bool eraseTrace = false;

            preHandleState();

            TapVerifier tapVerifier;
            if (tapVerifier.verifyTrace( traces[_id]) ){
                selection(_id);
                eraseTrace = true;
            }
            
            switch(this->state){
                case CREATE_POLYGON:
                    createPolygon(_id);
                    break;
                case FACE_SELECTED:    
                    this->state = GROW;
                    scene->enablePlane();
                    eraseTrace = true;
                    break;
                case GROW:
                    growSuggestion(_id);
                    eraseTrace = true;
                    break;
            }
            
            if (eraseTrace){
                traces.erase(_id);
            }
            
            postHandleState();
            modeling->updateScene();
        }
        
        
        
        void finishTrace(int _id){
            map<int, Trace> &traces = this->sketch.getTraces();
            traces[_id].filter();
            
            handleState(_id);
        }
};

#endif /* MY_INTERPRETER_H */
